\ FILES.TXT Information on Files and their interface in ZF. 9. The File System and Handles The file system interface in ZF uses Handles to talk to DOS, that is only number representing the File ID is passed to DOS from Forth. To make the interface a simple and clean as possible, you the Forth programmer need never deal with the details of how this works, you only need know that handles are created with the word HANDLE, handles are arrays within which special file information is stored, and when a handles name is executed, it returns an address which is the address that is passed to the handle file control words. Word definitions and usage follow; Handle Words in ZF .FILES ( --- ) Print to the screen a list of the files currently open. .LOADED ( --- ) Print a list of the files that have been loaded, This list is used to locate the source file for a particular word that has been compiled. ">$ ( char_addr count --- counted_string ) Drops the count, and decrements char_addr by one, to convert to a counted string. $>HANDLE ( a1 handle --- ) Move the COUNTED STRING a1 into the filename field of handle. $>EXT ( a1 handle --- ) Move the counted string a1 into the extension field of handle, the extension string should not contain a decimal point, and should be exactly (3) three characters long. $HOPEN ( a1 --- return_code ) Close the current file if one is open, move the counted string from address a1 to the current handle on the handle stack. Return the result code from DOS as return_code. !HCB ( handle | text --- ) Picks up text from the input stream with word, and places the name into the handle. ?DEF.EXT ( --- handle ) Conditionally applies the extension specified in the array DEFEXT to the filename in handle. DEFEXT is a counted string, three characters long plus the count. CHARREAD ( --- c1 ) Reads a character from the currently open file specified by SHNDL @, before using this word, you will need to initialize the sequential input buffer to empty, to force a refill from the currently selected file, by saying; INLEN OFF This will force a disk read on the next call to CHARREAD, assuring you get data from the file you selected. CLOSE ( --- ) Close the currently open file on SHNDL @, moves down one level on the handle stack, so another file may be open after performing this operation, but normally you will be able to operate on the handle in SHNDL, as an empty handle after performing CLOSE. CLR-HCB ( handle --- ) Clears the handle, to nulls, and resets the handle identifier field to -1 to indicate no file is open. CURPOINTER ( handle --- Double_current ) Returns the current 32-bit double pointer into the file specified by handle. DEFEXT ( --- a1 ) Returns the address of the default file extension that will be applied to any file to be opened, if no extension is specified in the filename when the HOPEN occurs. The address a1 is the address of a 4 byte array containing a count byte, and three extension bytes following. In no case should a string longer than 3 characters plus count be placed in DEFEXT. ENDFILE ( handle --- double_end ) Return the double_end number which represents the length of the file specified by handle. The file must already be open. EXHREAD ( a1 n1 handle segment --- n2 ) Read from file handle into the buffer specified by segment and address a1 for a length of bytes n1, return n2 the length of bytes actually read. The file must already be open. Useful for reading from a file into memory other than Forth's code segment. A read from a file is limited to 65535 bytes. EXHWRITE ( a1 n1 handle segment --- n2 ) Write from segment and address a1 for a length of n1 bytes to file handle, return n2 the length of bytes actually written. the file must already be open. Useful for writing from memory other than Forth code segment to a file. A write to a file is limited to 65535 bytes. FILE>TIB ( a1 --- ) Move the counted string filename from address a1 to the Terminal Input Buffer (TIB), available for use by !HCB. FLOAD ( filename --- ) Open and load the file specified by filename. HANDLE ( --- ) Create a handle with name . When is later executed, it returns the address of the handle array created. HANDLE>EXT ( handle --- a1 ) Steps from the handle address to the address of the file extension in the handle, if an extension exists, else it steps to the null following the filename. The address a1 will be the address of a decimal point character if the file contains an extension, or the address of a null if no extension was contained in the handle. HCLOSE ( handle --- return_code ) Close the file currently open on handle, and return the result code from DOS as return_code. HCREATE ( handle --- return_code ) Create the filename specified by handle, and return the DOS result code as return_code. HDELETE ( handle --- return_code ) Delete the filename as specified by handle, return the result code from DOS as return_code. HIDELINES ( --- ) Specifies that lines loaded with FLOAD NOT be displayed to the display screen. HOPEN ( handle --- return_code ) Given handle the address, open the filename in it, and return the result code from DOS as return_code. HREAD ( a1 n1 handle --- n2 ) Read from file handle into the buffer address a1 for length of bytes n1, return n2 the length of bytes actually read. The file must already be open. A read from a file is limited to 65535 bytes. HRENAME ( handle1 handle2 --- return_code ) Rename the filename specified by handle1 to be the name specified in handle2, return the DOS result code as return_code. HWRITE ( a1 n1 handle --- n2 ) Write from address a1 for length n1 bytes to file handle, return n2 the length of bytes actually written. The file must already be open. A write to a file is limited to 65535 bytes. LINEREAD ( --- a1 ) Reads lines from the current file, prebuffered by INBUF, which holds 1024 bytes. Returns a1 the address of OUTBUF, a 256 byte buffer used to hold lines read. When switching to a new file, you should use MOVEPOINTER to reset the file pointer to the beginning of the file, and reset INLEN to zero so the next LINEREAD will cause a read from the disk file. The read line length is limited to 255 bytes. LIST ( line_number --- ) List 18 lines starting at line_number from the currently open file. See also L N B OPEN FL LOAD ( line_number --- ) Start loading the currently open file, at line_number. Load through the end of the file if no errors are encountered. MOVEPOINTER ( double_offset handle --- ) Move the filepointer into the file handle to the offset location specified by double_offset. The file must already be open. PATHSET ( handle --- f1 ) Checks the file contained in handle, if it does not contain a path, then it applies the current drive and path to the handle. Returns f1 FALSE if it succeeded, else TRUE if it failed to read the path from DOS. RWMODE ( --- a1 ) A variable which holds the read/write attributes for any file to be opened by HOPEN, normally contains a two (2) for read/write, may be set to one (1) for write only, or to zero (0) for read only. SEEK ( d1 --- ) Position the file pointer for the file currently open on SHNDL @, to d1, that is SEEK to position d1. SEQDOWN ( --- ) Close the current file on the current level of the handle stack, and step down one level to the previous handle. The handle stack is four levels deep. SEQUP ( --- ) Step up one Handle on the handle stack, if there is a file open on that stack level, close it. The stack handle is four levels deep. SHOWLINES ( --- ) Specifies that lines loaded with FLOAD will be displayed to the display screen. Handle Fields A handle contains several fields, and words have been defined to traverse to the various fields, here is a picture of the data structure of a handle. +0 +1 +66 +68 [ count ] [ path & filename 00 ] [ attributes ] [ handle ] 1 byte 64 bytes + null 2 bytes 2 bytes ^ ^ ^ ^ | | | | handle >NAM >ATTRIB >HNDLE Each of the words in the above line, after handle, steps from the address returned by the handle, to the field indicated. Sample of LINEREAD usage. A sequential line read word LINEREAD is provided, which reads a line at a time from the file open in SHNDL, returning an address of a counted string which will include the CRLF characters at the end of the line, so you will need to strip them off if you don't want them. the LINEREAD word is used as follows; : sample ( filename --- ) open \ open a file 0.0 seek \ reset file pointer inlen off \ clear input buffer begin lineread \ read a line, returns \ an address of counted $ dup c@ \ check for length <>0 while cr count 2- type \ type line just read \ without the CRLF chars. repeat drop \ repeat till file empty. close ; \ close the file. This simple example may seem complicated, but it really is easy to read the lines of a sequential file, and writing is just as easy. The word LINEREAD automatically buffers the reads from disk in a 1k buffer to minimize the number of DOS calls performed. Lines up to 255 characters can be read with LINEREAD, longer lines or lines not terminated by a LF will be truncated to 255 characters.